#include "ODN_GameWorld.h"

namespace ouden {

CGameWorld::CGameWorld()
{
	//ctor
}

CGameWorld::~CGameWorld()
{
	//dtor
}

void CGameWorld::update()
{
	
	//Loop through all the entities in the game world and update them
	for (int i=0;i<m_pEntities.size();i++) {
		m_pEntities[i]->update();
	}
	
}
/*
//Main template function to create an entity of the specified type and give
// it a name. 
//Usage eg. CRocketEntity* pRocket = createEntity<CRocketEntity>("rocket1");
template<class TEntityType>
TEntityType* CGameWorld::createEntity(String sName)
{
	
	//Check that an entity with the same name does not already exist
	if (m_pEntityMap.end() == m_pEntityMap.find(sName)) {
		
		//Create a new entity of type T with the specified name
		TEntityType* newEntity = new TEntityType(sName);
		
		//Add the new entity to the array of all entities
		//NOTE: This will not compile if T is not derived from CBaseEntity, which protects against passing random types to this function
		m_pEntities.push_back(newEntity);
		
		//Add the new entity to the entity map with its name
		m_pEntityMap[sName] = newEntity;
		
		//Return the new entity as a pointer to its own type with no need to cast
		return newEntity;
		
	}
	else
	{
		
		//The name is already in use
		std::cout << "An entity named " << sName << " already exists. New entity not created." << std::endl;
		
		return 0;
		
	}
	
}*/

/*//Call the entity's static create function from the registered function 
		// pointer to create a new instance of the entity
		CBaseEntity* newEntity = (*fpCreateFunction)();


		//Get the factory function pointer from the map
		Ptr2EntFactory fpFactory = itMapEntry->second;
		
		//Call the factory function to create a new entity of the correct type
		CBaseEntity* pNewEntity = (*fpFactory)();
		
		//Add the new entity to the array of all entities
		//NOTE: This will not compile if T is not derived from CBaseEntity, which protects against passing random types to this function
		m_pEntities.push_back(pNewEntity);
		
		//Add the new entity to the entity map with its name
		m_pEntityMap[sName] = pNewEntity;
		
		//Return the new entity as a pointer to its own type with no need to cast
		return newEntity;
		
		*/

//Creates a new entity by type identifying string and returns a pointer to it
CBaseEntity* CGameWorld::createEntity(String sType, String sName)
{
	
	//Create a temporary variable to hold the iterator returned from find
	Map<String, CBaseEntity*>::iterator itMapEntry;
	
	//Try to find the entity name in the map
	itMapEntry = m_pEntityMap.find(sName);
	
	//Check that an entity with the same name does not already exist
	if (m_pEntityMap.end() == itMapEntry) {
		
		//TODO: Find sType in entity factory map and check for existence
		
		//Create a temporary variable to hold the iterator returned from find
		Map<String, Ptr2EntFactory>::iterator itFactoryMapEntry;
	
		//Try to find the entity name in the map
		itFactoryMapEntry = m_fpEntityFactoryMap.find(sType);
		
		//Check that the requested entity type has been registered
		if (m_fpEntityFactoryMap.end() != itFactoryMapEntry) {
			
			//Get the factory function pointer from the map
			Ptr2EntFactory fpFactory = itFactoryMapEntry->second;
			
			//Call the factory function to create a new entity of the correct type
			//TODO: Decide whether need to pass sName to factory function for entity
			// constructors
			CBaseEntity* pNewEntity = (*fpFactory)(sName);
			
			//Add the new entity to the array of all entities
			m_pEntities.push_back(pNewEntity);
			
			//Now map the entity's name to its pointer
			
			//Create a new pair object to hold the new map entry
			std::pair<String, CBaseEntity*> paNewEntry(sName, pNewEntity);
			
			//Insert the new map entry
			m_pEntityMap.insert(paNewEntry);
			
			//Return the new entity as a pointer to its own type with no need to cast
			return pNewEntity;
			
		}
		else
		{
			
			//The entity type is not registered
			std::cout << "No entity of type " << sType << " has been registered. New entity not created." << std::endl;
			
			return 0;
			
		}
		
	}
	else
	{
		
		//The name is already in use
		std::cout << "An entity named " << sName << " already exists. New entity not created." << std::endl;
		
		return 0;
		
	}
	
}

bool CGameWorld::registerEntity(String sType, Ptr2EntFactory fpEntFactory)
{
	
	//Create a temporary variable to hold the iterator returned from find
	Map<String, Ptr2EntFactory>::iterator itMapEntry;
	
	//Try to find the entity type in the map
	itMapEntry = m_fpEntityFactoryMap.find(sType);
	
	//Check that an entity with the same type string has not already been registered
	if (m_fpEntityFactoryMap.end() == itMapEntry) {
		
		//Create a new pair object to hold the new map entry
		std::pair<String, Ptr2EntFactory> paNewEntry(sType, fpEntFactory);
		
		//Insert the new map entry
		m_fpEntityFactoryMap.insert(paNewEntry);
		
		return true;
		
	}
	else
	{
		
		//The type identifier string is already in use
		std::cout << "An entity of type " << sType << " has already been registered. Returning unsuccessful." << std::endl;
		
		return false;
		
	}
	
}

//Returns a pointer to an entity referenced by name
CBaseEntity* CGameWorld::findEntity(String sName)
{
	
	//Search for the named entity and put the result into an iterator
	Map<String, CBaseEntity*>::const_iterator itFoundEntity = 
		m_pEntityMap.find(sName);
	
	//Check if the entity was found
	if (m_pEntityMap.end() == itFoundEntity)
	{
		//The named entity could not be found in the map 
		
		std::cout << "Entity named " << sName << " not found in game world" << std::endl;
		
		return 0;
	}
	else
	{
		return (*itFoundEntity).second;
	}
	
}

//Removes an entity from the game world and destroys it
bool CGameWorld::destroyEntity(CBaseEntity* &pEntity)
{
	
	assert(pEntity);
	
	//TODO: Possibly look into finding a different way to do this
	
	//Create a new iterator to store the position of the entity in the array 
	Array<CBaseEntity*>::iterator itIndex;
	//Find the element in the array 
	itIndex = std::find(m_pEntities.begin(), m_pEntities.end(), pEntity);
	
	//Make sure the entity was found in the array
	if (m_pEntities.end() != itIndex) {
		
		//Remove the entity from the array
		m_pEntities.erase(itIndex);
		
		//Remove the entity from the name map
		m_pEntityMap.erase(pEntity->getName());
		
		//Delete the entity
		delete pEntity;
		pEntity = 0;  //This works because the pointer is passed by reference
		
		return true;
		
	}
	else
	{
		
		//The entity was not found in the array, which is rather bad
		std::cout << "BAD ERROR: Entity passed for destruction was not found in array" << std::endl;
		
		//TODO: Decide what to do here
		
		return false;
		
	}
	
}

} //namespace ouden
